#pragma once
// ==================包含头文件====================
#include "hal/gpio.hpp"
#include "ti_msp_dl_config.h"
// ================== 包含头文件 ====================
#include <type_traits>

namespace hal::details_spi
{
    // ==================随配置变动部分====================
    //CS PORT一定要记得改
    using CS_SPI_PIN = hal::gpio<GPIOA_BASE, LCD_CS_PIN>;
    // ==================随配置变动部分====================

    template<uint32_t SPI_BASE>
    class spi_config{

    private:
        // 获取SPI硬件寄存器指针
        static SPI_Regs *get_base()
        {
            return reinterpret_cast<SPI_Regs *>(SPI_BASE);
        }


        /**
         * @brief 设置SPI时钟配置
         *
         * @param config 时钟配置结构体
         *
         * 1. 选择时钟源(BUSCLK/MFCLK/LFCLK)
         * 2. 设置时钟分频比(1-8)
         */
        static inline void set_clock(const DL_SPI_ClockConfig *config) noexcept
        {
            DL_SPI_setClockConfig(get_base(), config);
        }
    public:
        /**
         * @brief 初始化SPI控制器
         *
         * @param config SPI配置结构体
         *
         * 使用说明:
         * 1. 配置SPI工作模式(控制器/外设)
         * 2. 设置数据帧格式(时钟极性/相位)
         * 3. 设置数据位大小(4-16位)
         * 4. 设置位传输顺序(MSB/LSB)
         * 5. 设置片选引脚(硬件模式)
         */
        static inline void init(const DL_SPI_Config *config) noexcept
        {
            DL_SPI_init(get_base(), config);
        }

        /**
         * @brief 使能SPI控制器
         *
         * 在初始化完成后使能SPI外设，开始工作
         */
        static inline void enable() noexcept
        {
            DL_SPI_enable(get_base());
        }

        /**
         * @brief 禁用SPI控制器
         *
         * 停止SPI工作，降低功耗
         */
        static inline void disable() noexcept
        {
            DL_SPI_disable(get_base());
        }

        /**
         * @brief 拉低片选信号(软件控制)
         *
         * 注意: 需配合外部GPIO实现
         */
        static inline void cs_low() noexcept
        {
            CS_SPI_PIN::low();

        }

        /**
         * @brief 拉高片选信号(软件控制)
         *
         * 注意: 需配合外部GPIO实现
         */
        static inline void cs_high() noexcept
        {
            CS_SPI_PIN::high();
        }

        /**
         * @brief 阻塞式发送单字节数据
         *
         * @param data 要发送的数据(8位)
         *
         * 函数会等待发送FIFO有空闲位置后再发送数据
         */
        static inline void send_byte(uint8_t data) noexcept
        {
            DL_SPI_transmitDataBlocking8(get_base(), data);
        }

        /**
         * @brief 阻塞式发送多字节数据
         *
         * @param data 数据缓冲区指针
         * @param len 数据长度(字节数)
         *
         * 循环发送缓冲区中的所有数据，等待每个字节发送完成
         */
        static inline void send_bytes(uint8_t *data, uint32_t len) noexcept
        {
            for (uint32_t i = 0; i < len; i++)
            {
                DL_SPI_transmitDataBlocking8(get_base(), data[i]);
            }
        }

        /**
         * @brief 阻塞式接收单字节数据
         *
         * @return uint8_t 接收到的数据(8位)
         *
         * 函数会等待接收FIFO有数据后再读取
         */
        static inline uint8_t receive_byte() noexcept
        {
            return DL_SPI_receiveDataBlocking8(get_base());
        }



        /**
          * @brief 使能SPI DMA 中断
          */
        static inline void enable_dma_transmitevent() noexcept
        {
            DL_SPI_enableDMATransmitEvent(get_base());
        }

        /**
          * @brief 关闭SPI DMA 中断
          */

        static inline void disable_dma_transmitevent() noexcept
        {
            DL_SPI_disableDMATransmitEvent(get_base());
        }

        static inline void enable_irq() noexcept
        {
            if constexpr (SPI_BASE == SPI0_BASE)
                NVIC_EnableIRQ(SPI0_INT_IRQn);
            else if constexpr (SPI_BASE == SPI1_BASE)
                NVIC_EnableIRQ(SPI1_INT_IRQn);
        }

        // 获取SPI中断
        static constexpr IRQn_Type get_isr()
        {
            if constexpr (SPI_BASE == SPI0_BASE)
                return SPI0_INT_IRQn;
            else if constexpr (SPI_BASE == SPI1_BASE)
                return SPI1_INT_IRQn;
        }

        static inline DL_SPI_IIDX get_pending_interrupt() noexcept
        {
            return DL_SPI_getPendingInterrupt(get_base());
        }
    };


} // namespace hal::details_spi

namespace hal
{

/**
 * @class spi
 * @brief SPI控制器封装类
 * 
 * @tparam SpiTag SPI实例标签(SPI0_tag或SPI1_tag)
 * 
 * 封装了TI MSPM0 SPI驱动库的功能，提供简化的SPI操作接口：
 * 1. 初始化SPI控制器
 * 2. 片选信号控制
 * 3. 单字节/多字节数据传输
 * 4. 阻塞式发送/接收操作
 */
    using spi0 = details_spi::spi_config<SPI0_BASE>;
    using spi1 = details_spi::spi_config<SPI1_BASE>;

}



